//
//  JKFileExplorerEngine.m
//  TestCocoaHTTPserver
//
//  Created by albert on 2018/11/8.
//  Copyright © 2018 albert. All rights reserved.
//

#import "JKFileExplorerEngine.h"
#import "JKFileManager.h"
#import "JKFileExplorerItem.h"
#import "SSZipArchive.h"

#if __has_include(<AFNetworking/AFNetworking.h>)
#import <AFNetworking/AFNetworking.h>
#elif __has_include("AFNetworking.h")
#import "AFNetworking.h"
#else
#endif
@interface JKFileExplorerEngine ()

@end

/** 队列 */
static dispatch_queue_t explorerEngineQueue_;

@implementation JKFileExplorerEngine

+ (dispatch_queue_t)explorerEngineQueue {
    if (!explorerEngineQueue_) {
        explorerEngineQueue_ = dispatch_queue_create("com.albert.JKFileExplorerEngine", DISPATCH_QUEUE_CONCURRENT);
    }
    return explorerEngineQueue_;
}

+ (void)destroyEngineQueue {
    
    if (explorerEngineQueue_) {
        explorerEngineQueue_ = nil;
    }
}



/** 根据文件夹路径获取文件名列表 */
+ (void)fetchFileNameListWithDirectoryPath:(NSString *)directoryPath
                                   success:(void(^)(NSString *directoryPath, NSArray <NSString *> *fileNameList))success
                                   failure:(void(^)(NSError *error))failure {
    
    dispatch_async([JKFileExplorerEngine explorerEngineQueue], ^{
        
        NSError *error = nil;
        
        NSArray *fileNameArr = [JKFileManager listFilesInDirectoryAtPath:directoryPath deep:NO error:&error];
        
        if (error) { // 出错了
            
            dispatch_async(dispatch_get_main_queue(), ^{
                
                !failure ? : failure(error);
            });
            
            return;
        }
        
        dispatch_async(dispatch_get_main_queue(), ^{
            
            !success ? : success(directoryPath, fileNameArr);
        });
    });
}

/** 根据fileIetm获取文件名列表 */
+ (void)fetchFileNameListWithFileItem:(JKFileExplorerItem *)fileItem
                              success:(void(^)(JKFileExplorerItem *fileItem, NSArray <NSString *> *fileNameList))success

                              failure:(void(^)(NSError *error))failure{
    [self fetchFileNameListWithDirectoryPath:fileItem.filePath success:^(NSString *directoryPath, NSArray<NSString *> *fileNameList) {
        
        fileItem.subFileNameList = fileNameList;
        
        !fileItem.loadSubFileNameListComplete ? : fileItem.loadSubFileNameListComplete(fileItem);
        
        !success ? : success(fileItem, fileNameList);
        
    } failure:^(NSError *error) {
        
        fileItem.fetchSubFileNameListError = error;
        
        !fileItem.loadSubFileNameListComplete ? : fileItem.loadSubFileNameListComplete(fileItem);
        
        !failure ? : failure(error);
    }];
}

/** 根据文件夹路径获取fileItem列表 排序参数 */
+ (void)fetchFileItemListWithDirectoryPath:(NSString *)directoryPath
                                sortConfig:(JKFileExplorerSortConfig)sortConfig
                                   success:(void(^)(NSString *directoryPath, NSArray <JKFileExplorerItem *> *fileItemList, NSArray <JKFileExplorerItem *> *folderList, NSArray <JKFileExplorerItem *> *fileList))success
                                   failure:(void(^)(NSError *error))failure{
    
}

/** 根据文件夹路径和文件名列表获取fileItem列表 排序参数 */
+ (void)fetchFileItemListWithDirectoryPath:(NSString *)directoryPath
                              fileNameList:(NSArray <NSString *> *)fileNameList
                                sortConfig:(JKFileExplorerSortConfig)sortConfig
                                   success:(void(^)(NSString *directoryPath, NSArray <JKFileExplorerItem *> *fileItemList, NSArray <JKFileExplorerItem *> *folderList, NSArray <JKFileExplorerItem *> *fileList, NSMutableDictionary *filePathItemDict))success{
    
    [self fetchFileItemListWithDirectoryPath:directoryPath fileNameList:fileNameList finish:^(NSString *directoryPath, NSArray<JKFileExplorerItem *> *fileItemList, NSMutableDictionary *filePathItemDict) {
        
        [self sortFileItemList:fileItemList sortConfig:sortConfig finish:^(NSArray<JKFileExplorerItem *> *fileItemList, NSArray<JKFileExplorerItem *> *folderList, NSArray<JKFileExplorerItem *> *fileList) {
            
            !success ? : success(directoryPath, fileItemList, folderList, fileList, filePathItemDict);
        }];
    }];
}

/** 根据文件夹路径获取fileItem列表 未排序 */
+ (void)fetchFileItemListWithDirectoryPath:(NSString *)directoryPath
                                   success:(void(^)(NSString *directoryPath, NSArray <JKFileExplorerItem *> *fileItemList, NSMutableDictionary *filePathItemDict))success
                                   failure:(void(^)(NSError *error))failure{
    
    [self fetchFileNameListWithDirectoryPath:directoryPath success:^(NSString *directoryPath, NSArray<NSString *> *fileNameList) {
        
        [self fetchFileItemListWithDirectoryPath:directoryPath fileNameList:fileNameList finish:success];
        
    } failure:failure];
}

/** 根据文件夹路径和fileNameList获取fileItem列表 未排序 */
+ (void)fetchFileItemListWithDirectoryPath:(NSString *)directoryPath
                              fileNameList:(NSArray <NSString *> *)fileNameList
                                   finish:(void(^)(NSString *directoryPath, NSArray <JKFileExplorerItem *> *fileItemList, NSMutableDictionary *filePathItemDict))finish{
    
    dispatch_async([JKFileExplorerEngine explorerEngineQueue], ^{
        
        NSMutableArray *itemArr = [NSMutableArray array];
        
        NSMutableDictionary *filePathItemDict = [NSMutableDictionary dictionary];
        
        // 遍历fileNameList
        [fileNameList enumerateObjectsUsingBlock:^(NSString * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
            
            @autoreleasepool {
                
                // 拼接文件路径
                NSString *filePath = [directoryPath stringByAppendingPathComponent:obj];
                
                // 创建JKFileExplorerItem
                JKFileExplorerItem *item = [self createFileItemWithFilePath:filePath];
                
                [filePathItemDict setObject:item forKey:item.filePath];
                
                if (item.isFolder) {
                    
                    [self fetchFileNameListWithFileItem:item success:^(JKFileExplorerItem *fileItem, NSArray<NSString *> *fileNameList) {
                        
                    } failure:^(NSError *error) {
                        
                    }];
                }
                
                // 添加到数组
                [itemArr addObject:item];
            }
        }];
        
        dispatch_async(dispatch_get_main_queue(), ^{
           
            !finish ? : finish(directoryPath, itemArr, filePathItemDict);
        });
    });
}

/** 对fileItem列表排序 */
+ (void)sortFileItemList:(NSArray <JKFileExplorerItem *> *)fileItemList
              sortConfig:(JKFileExplorerSortConfig)sortConfig
                 finish:(void(^)(NSArray <JKFileExplorerItem *> *fileItemList, NSArray <JKFileExplorerItem *> *folderList, NSArray <JKFileExplorerItem *> *fileList))finish{
    
    dispatch_async([JKFileExplorerEngine explorerEngineQueue], ^{
       
        switch (sortConfig.folderLocation) {
            case JKFileExplorerSortFolderLocationTop: // 文件夹在上
            {
                [self sortFileItemListByFolderLocationTop:fileItemList sortConfig:sortConfig finish:^(NSArray<JKFileExplorerItem *> *fileItemList, NSArray<JKFileExplorerItem *> *folderList, NSArray<JKFileExplorerItem *> *fileList) {
                    
                    dispatch_async(dispatch_get_main_queue(), ^{
                        
                        !finish ? : finish(fileItemList, folderList, fileList);
                    });
                }];
            }
                break;
            case JKFileExplorerSortFolderLocationMix: // 文件夹和文件混在一起
            {
                [self sortFileItemListByFolderLocationMix:fileItemList sortConfig:sortConfig finish:^(NSArray<JKFileExplorerItem *> *fileItemList, NSArray<JKFileExplorerItem *> *folderList, NSArray<JKFileExplorerItem *> *fileList) {
                    
                    dispatch_async(dispatch_get_main_queue(), ^{
                        
                        !finish ? : finish(fileItemList, folderList, fileList);
                    });
                }];
            }
                break;
            case JKFileExplorerSortFolderLocationBottom: // 文件夹在下
            {
                [self sortFileItemListByFolderLocationBottom:fileItemList sortConfig:sortConfig finish:^(NSArray<JKFileExplorerItem *> *fileItemList, NSArray<JKFileExplorerItem *> *folderList, NSArray<JKFileExplorerItem *> *fileList) {
                    
                    dispatch_async(dispatch_get_main_queue(), ^{
                        
                        !finish ? : finish(fileItemList, folderList, fileList);
                    });
                }];
            }
                break;
                
            default:
                break;
        }
    });
}

+ (void)sortFileItemListByFolderLocationTop:(NSArray <JKFileExplorerItem *> *)fileItemList sortConfig:(JKFileExplorerSortConfig)sortConfig finish:(void(^)(NSArray <JKFileExplorerItem *> *fileItemList, NSArray <JKFileExplorerItem *> *folderList, NSArray <JKFileExplorerItem *> *fileList))finish{
    
    [self sortFileItemListByFolderLocationMix:fileItemList sortConfig:sortConfig finish:^(NSArray<JKFileExplorerItem *> *fileItemList, NSArray<JKFileExplorerItem *> *folderList, NSArray<JKFileExplorerItem *> *fileList) {
        
        NSMutableArray *arrM = [NSMutableArray array];
        
        [arrM addObjectsFromArray:folderList];
        [arrM addObjectsFromArray:fileList];
        
        !finish ? :finish(arrM, folderList, fileList);
    }];
}

+ (NSComparisonResult)sortWithObj1:(id)obj1 obj2:(id)obj2 sortType:(JKFileExplorerSortType)sortType{
    
    switch (sortType) {
        case JKFileExplorerSortTypeAsc: // 升序
        {
            return [obj1 compare:obj2];
        }
            break;
        case JKFileExplorerSortTypeDesc: // 降序
        {
            return [obj2 compare:obj1];
        }
            break;
            
        default:
            break;
    }
}

+ (void)sortFileItemListByFolderLocationMix:(NSArray <JKFileExplorerItem *> *)fileItemList sortConfig:(JKFileExplorerSortConfig)sortConfig finish:(void(^)(NSArray <JKFileExplorerItem *> *fileItemList, NSArray <JKFileExplorerItem *> *folderList, NSArray <JKFileExplorerItem *> *fileList))finish{
    
    NSArray *arr = [fileItemList sortedArrayUsingComparator:^NSComparisonResult(JKFileExplorerItem *  _Nonnull obj1, JKFileExplorerItem *  _Nonnull obj2) {
        
        switch (sortConfig.sortIdentifier) {
            case JKFileExplorerSortIdentifierFileName:
            {
                return [self sortWithObj1:obj1.fileName.lowercaseString obj2:obj2.fileName.lowercaseString sortType:sortConfig.sortType];
            }
                break;
            case JKFileExplorerSortIdentifierFileSize:
            {
                if ([obj1.fileSize longLongValue] == [obj2.fileSize longLongValue]) { // 大小一样
                    
                    // 按名称排序
                    return [self sortWithObj1:obj1.fileName.lowercaseString obj2:obj2.fileName.lowercaseString sortType:sortConfig.sortType];
                }
                
                return [self sortWithObj1:obj1.fileSize obj2:obj2.fileSize sortType:sortConfig.sortType];
            }
                break;
            case JKFileExplorerSortIdentifierCreateDate:
            {
                if ([obj1.creationDateString isEqualToString:obj2.creationDateString]) { // 创建日期一样
                    
                    // 按名称排序
                    return [self sortWithObj1:obj1.fileName.lowercaseString obj2:obj2.fileName.lowercaseString sortType:sortConfig.sortType];
                }
                
                return [self sortWithObj1:obj1.creationDate obj2:obj2.creationDate sortType:sortConfig.sortType];
            }
                break;
            case JKFileExplorerSortIdentifierModificationDate:
            {
                if ([obj1.modificationDateString isEqualToString:obj2.modificationDateString]) { // 修改日期一样
                    
                    // 判断创建日期
                    if ([obj1.creationDateString isEqualToString:obj2.creationDateString]) { // 创建日期一样
                        
                        // 按名称排序
                        return [self sortWithObj1:obj1.fileName.lowercaseString obj2:obj2.fileName.lowercaseString sortType:sortConfig.sortType];
                    }
                    
                    // 按创建日期排序
                    return [self sortWithObj1:obj1.creationDate obj2:obj2.creationDate sortType:sortConfig.sortType];
                }
                
                return [self sortWithObj1:obj1.modificationDate obj2:obj2.modificationDate sortType:sortConfig.sortType];
            }
                break;
                
            default:
                break;
        }
    }];
    
    NSMutableArray *folderArr = [NSMutableArray array];
    
    NSMutableArray *fileArr = [NSMutableArray array];
    
    [arr enumerateObjectsUsingBlock:^(JKFileExplorerItem *  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
        
        if (obj.isFolder) { // 文件夹
            
            [folderArr addObject:obj];
            
        } else {
            
            [fileArr addObject:obj];
        }
    }];
    
    !finish ? : finish(arr, folderArr, fileArr);
}

+ (void)sortFileItemListByFolderLocationBottom:(NSArray <JKFileExplorerItem *> *)fileItemList sortConfig:(JKFileExplorerSortConfig)sortConfig finish:(void(^)(NSArray <JKFileExplorerItem *> *fileItemList, NSArray <JKFileExplorerItem *> *folderList, NSArray <JKFileExplorerItem *> *fileList))finish{
    
    [self sortFileItemListByFolderLocationMix:fileItemList sortConfig:sortConfig finish:^(NSArray<JKFileExplorerItem *> *fileItemList, NSArray<JKFileExplorerItem *> *folderList, NSArray<JKFileExplorerItem *> *fileList) {
        
        NSMutableArray *arrM = [NSMutableArray array];
        
        [arrM addObjectsFromArray:fileList];
        [arrM addObjectsFromArray:folderList];
        
        !finish ? :finish(arrM, folderList, fileList);
    }];
}

/** 根据文件夹路径异步创建一个fileItem */
+ (void)fetchFileItemWithDirectoryPath:(NSString *)directoryPath
                               finish:(void(^)(NSString *directoryPath, JKFileExplorerItem *fileItem))finish{
    
    dispatch_async([JKFileExplorerEngine explorerEngineQueue], ^{
        
        JKFileExplorerItem *item = [self createFileItemWithFilePath:directoryPath];
        
        dispatch_async(dispatch_get_main_queue(), ^{
           
            !finish ? : finish(directoryPath, item);
        });
    });
}

/** 根据文件路径创建JKFileExplorerItem */
+ (JKFileExplorerItem *)createFileItemWithFilePath:(NSString *)filePath {
    
    JKFileExplorerItem *item = [[JKFileExplorerItem alloc] init];
    
    item.filePath = filePath;
    
    NSError *error = nil;
    
//    if (![JKFileManager isExistsAtPath:filePath]) { // 路径不存在
//        
//        error = [NSError errorWithDomain:NSCocoaErrorDomain code:-1 userInfo:@{NSLocalizedDescriptionKey : @"路径不存在"}];
//        
//        item.createItemError = error;
//        
//        return item;
//    }
    
    // 获取文件属性
    NSDictionary *fileAttr = [JKFileManager attributesOfItemAtPath:filePath error:&error];
    
    if (error) { // 获取文件属性出错
        
        item.fileType = NSFileTypeRegular;
        item.fileSize = @0;
        item.fileAttributeError = error;
        
    } else {// 获取文件属性成功
        
        item.fileType         = [fileAttr objectForKey:NSFileType];
        item.fileSize         = [fileAttr objectForKey:NSFileSize];
        item.creationDate     = [fileAttr objectForKey:NSFileCreationDate];
        item.modificationDate = [fileAttr objectForKey:NSFileModificationDate];
    }
    
    item.deletable = [JKFileManager isDeletableItemAtPath:filePath];
    
    return item;
}

/** 去除文件后缀，若最后一位是. 也移除掉 */
+ (NSString *)stringByDeletingPathExtensionAndDotWithString:(NSString *)string{
    
    if ([string length] <= 0) {
        
        return string;
    }
    
    NSString *subString = [string stringByDeletingPathExtension];
    
    if (subString.length <= 0) {
        
        return string;
    }
    
    NSString *lastCharacter = [subString substringFromIndex:subString.length - 1];
    
    if ([lastCharacter isEqualToString:@"."]) {
        
        subString = [subString substringToIndex:subString.length - 1];
    }
    
    return subString;
}

/**
 * 检查重名，并返回合适的文件路径
 * filePath : 要检查重名的路径
 * sourceFilePath : 源文件，用于判断是否文件夹，来决定重名后的命名方式
 * 如果是文件夹，则直接加(1)，文件则在后缀前加(1)
 */
+ (NSString *)checkDuplicationNameWithFilePath:(NSString *)filePath sourceFilePath:(NSString *)sourceFilePath{
    
    BOOL isDirectory = NO;
    
    // 检查源文件路径
    if (![JKFileManager isExistsAtPath:sourceFilePath isDirectory:&isDirectory]) {
        
        return filePath;
    }
    
    return [self checkDuplicationNameWithFilePath:filePath isFolder:isDirectory];
}

/**
 * 检查重名，并返回合适的文件路径
 * filePath : 要检查重名的路径
 * isFolder : 是否文件夹，决定重名后的命名方式
 * 如果是文件夹，则直接加(1)，文件则在后缀前加(1)
 */
+ (NSString *)checkDuplicationNameWithFilePath:(NSString *)filePath isFolder:(BOOL)isFolder{
    
    NSString *destinationPath = [filePath copy];
    
    // 检查目标文件路径
    if (![JKFileManager isExistsAtPath:destinationPath]) {
        
        return destinationPath;
    }
    
    NSString *jointString1 = @"";
    NSString *jointString2 = @"";
    
    if (isFolder) {
        
        jointString1 = destinationPath;
        
    } else {
        
        // 判断是否重名
        
        // 文件后缀
        NSString *pathExtension = [destinationPath pathExtension];
        
        // 文件后缀是空字符串
        if (!pathExtension || [pathExtension isEqualToString:@""]) {
            
            NSString *lastCharacter = [destinationPath substringFromIndex:destinationPath.length - 1];
            
            if ([lastCharacter isEqualToString:@"."]) {
                
                if (destinationPath.length <= 1) {
                    
                    jointString1 = @"";
                    
                } else {
                    
                    jointString1 = [destinationPath substringToIndex:destinationPath.length - 1];
                }
                
                jointString2 = lastCharacter;
                
            } else {
                
                jointString1 = destinationPath;
                jointString2 = @"";
            }
            
        } else {
            
            jointString1 = [destinationPath substringToIndex:destinationPath.length - pathExtension.length - 1];
            
            jointString2 = [destinationPath substringFromIndex:destinationPath.length - pathExtension.length - 1];
        }
        
    }
    
    int index = 0;
    
    while ([JKFileManager isExistsAtPath:destinationPath]) {
        
        index++;
        
        destinationPath = [[jointString1 stringByAppendingString:[NSString stringWithFormat:@"(%d)", index]] stringByAppendingString:jointString2];
    }
    
    return destinationPath;
}

/** 解压文件 */
+ (void)unZipWithFileItem:(JKFileExplorerItem *)fileItem
                 progress:(void(^)(CGFloat progress))progress
                 complete:(void (^_Nullable)(NSString *originalPath, NSString *unZippedPath, BOOL succeeded, NSError * _Nullable error))complete{
    
    if (!fileItem || !fileItem.filePath) {
        
        !complete ? : complete(nil, nil, NO, [NSError errorWithDomain:NSCocoaErrorDomain code:-1 userInfo:@{NSLocalizedDescriptionKey : @"传入参数为空"}]);
        
        return;
    }
    
    dispatch_async([self explorerEngineQueue], ^{
        
        // 去除.zip
        NSString *destinationPath = [self stringByDeletingPathExtensionAndDotWithString:fileItem.filePath];
        
        // 检查重名，解压的文件都会放在文件夹中
        destinationPath = [JKFileExplorerEngine checkDuplicationNameWithFilePath:destinationPath isFolder:YES];
        
        // 开始解压
        [SSZipArchive unzipFileAtPath:fileItem.filePath toDestination:destinationPath progressHandler:^(NSString * _Nonnull entry, unz_file_info zipInfo, long entryNumber, long total) {
            
            !progress ? : progress(entryNumber * 1.0 / (total * 1.0));
            
            NSLog(@"解压中%@ -->%ld -->%ld", [NSThread currentThread], entryNumber , total);
            
        } completionHandler:^(NSString * _Nonnull path, BOOL succeeded, NSError * _Nullable error) {
            
            dispatch_async(dispatch_get_main_queue(), ^{
                
                !complete ? : complete(path, destinationPath, succeeded, error);
            });
        }];
    });
}

/** 批量压缩文件 progress在子线程回调 */
+ (void)multiZipWithFileItems:(NSArray <JKFileExplorerItem *> *)fileItems
                  zipFilePath:(NSString *)zipFilePath
                     password:(NSString *)password
                     progress:(void(^)(CGFloat progress))progress
                     complete:(void (^_Nullable)(NSString *zippedPath, BOOL succeeded, NSError * _Nullable error))complete{
    
    if (!fileItems || fileItems.count <= 0) {
        
        !complete ? : complete(nil, NO, [NSError errorWithDomain:NSCocoaErrorDomain code:-1 userInfo:@{NSLocalizedDescriptionKey : @"传入参数为空"}]);
        
        return;
    }
    
    dispatch_async([self explorerEngineQueue], ^{
        
        NSMutableArray *arrM = [NSMutableArray array];
        
        for (JKFileExplorerItem *fileItem in fileItems) {
            
            if (fileItem.filePath) {
                
                [arrM addObject:fileItem.filePath];
            }
        }
        
        if (arrM.count <= 0) {
            
            dispatch_async(dispatch_get_main_queue(), ^{
            
                !complete ? : complete(nil, NO, [NSError errorWithDomain:NSCocoaErrorDomain code:-1 userInfo:@{NSLocalizedDescriptionKey : @"传入数组中对象无效"}]);
            });
            
            return;
        }
        
        // 检查重名，压缩后是个文件
        NSString *destinationPath = [JKFileExplorerEngine checkDuplicationNameWithFilePath:zipFilePath isFolder:NO];
        
        BOOL success = [SSZipArchive createZipFileAtPath:destinationPath withFilesAtPaths:arrM withPassword:password];
        
        dispatch_async(dispatch_get_main_queue(), ^{
            
            !complete ? : complete(destinationPath, success, nil);
        });
    });
}

/** 压缩文件 progress在子线程回调 */
+ (void)zipWithFileItem:(JKFileExplorerItem *)fileItem
               password:(NSString *)password
               progress:(void(^)(CGFloat progress))progress
               complete:(void (^_Nullable)(NSString *originalPath, NSString *zippedPath, BOOL succeeded, NSError * _Nullable error))complete{
    
    if (!fileItem || !fileItem.filePath) {
        
        !complete ? : complete(nil, nil, NO, [NSError errorWithDomain:NSCocoaErrorDomain code:-1 userInfo:@{NSLocalizedDescriptionKey : @"传入参数为空"}]);
        
        return;
    }
    
    dispatch_async([self explorerEngineQueue], ^{
        
        // 检查重名，压缩后是个文件
        NSString *destinationPath = [JKFileExplorerEngine checkDuplicationNameWithFilePath:[fileItem.filePath stringByAppendingString:@".zip"] isFolder:NO];
        
        if (fileItem.isFolder) {
            
            BOOL success = [SSZipArchive createZipFileAtPath:destinationPath withContentsOfDirectory:fileItem.filePath keepParentDirectory:YES withPassword:password andProgressHandler:^(NSUInteger entryNumber, NSUInteger total) {
                
                !progress ? : progress(entryNumber * 1.0 / (total * 1.0));
                
                NSLog(@"压缩中%@ -->%ld -->%ld", [NSThread currentThread], entryNumber , total);
            }];
            
            dispatch_async(dispatch_get_main_queue(), ^{
                
                !complete ? : complete(fileItem.filePath, destinationPath, success, nil);
            });
            
        } else {
            
            BOOL success = [SSZipArchive createZipFileAtPath:destinationPath withFilesAtPaths:@[fileItem.filePath] withPassword:password];
            
            dispatch_async(dispatch_get_main_queue(), ^{
                
                !complete ? : complete(fileItem.filePath, destinationPath, success, nil);
            });
        }
    });
}

/** 批量移动文件 */
+ (void)multiMoveItemAtPaths:(NSArray <NSString *> *)paths
                     toPaths:(NSArray <NSString *> *)toPaths
                    progress:(void(^)(CGFloat progress))progress
                    complete:(void(^)(NSArray <NSString *> *successPaths, NSArray <NSString *> *failurePaths))complete{
    
    if (paths.count != toPaths.count) {
        
        !complete ? : complete(nil, nil);
        
        return;
    }
    
    [self _multiMoveItemAtPaths:paths toPaths:toPaths progress:progress complete:complete];
}

+ (void)_multiMoveItemAtPaths:(NSArray <NSString *> *)paths
                      toPaths:(NSArray <NSString *> *)toPaths
                     progress:(void(^)(CGFloat progress))progress
                     complete:(void(^)(NSArray <NSString *> *successPaths, NSArray <NSString *> *failurePaths))complete{
    
    static NSMutableArray *multiMoveSuccessArr = nil;
    
    static NSMutableArray *multiMoveFailureArr = nil;
    
    if (!multiMoveSuccessArr) {
        
        multiMoveSuccessArr = [NSMutableArray array];
    }
    
    if (!multiMoveFailureArr) {
        
        multiMoveFailureArr = [NSMutableArray array];
    }
    
    if (paths.count <= 0) {
        
        dispatch_async(dispatch_get_main_queue(), ^{
            
            !complete ? : complete(multiMoveSuccessArr, multiMoveFailureArr);
            
            multiMoveSuccessArr = nil;
            multiMoveFailureArr = nil;
        });
        
        return;
    }
    
    dispatch_async([self explorerEngineQueue], ^{
        
        NSError *error = nil;
        
        NSMutableArray *tmpPaths = [NSMutableArray arrayWithArray:paths];
        NSMutableArray *tmpToPaths = [NSMutableArray arrayWithArray:toPaths];
        
        NSString *fromPath = tmpPaths.firstObject;
        NSString *toPath = tmpToPaths.firstObject;
        
        NSString *destinationPath = [JKFileExplorerEngine checkDuplicationNameWithFilePath:toPath sourceFilePath:fromPath];
        
        NSLog(@"开始移动:\n%@至\n%@", fromPath, toPath);
        
        BOOL success = [JKFileManager moveItemAtPath:fromPath toPath:destinationPath error:&error];
        
        [tmpPaths removeObjectAtIndex:0];
        [tmpToPaths removeObjectAtIndex:0];
        
        if (error || !success) {
            
            [multiMoveFailureArr addObject:destinationPath];
            
            NSLog(@"移动失败:\n%@至\n%@", fromPath, toPath);
            
        } else {
            
            [multiMoveSuccessArr addObject:destinationPath];
            
            NSLog(@"移动成功:\n%@至\n%@", fromPath, toPath);
        }
        
        CGFloat finishCount = (multiMoveSuccessArr.count + multiMoveFailureArr.count) * 1.0 ;
        
        !progress ? : progress(finishCount / ((finishCount + multiMoveFailureArr.count) * 1.0));
        
        [self _multiMoveItemAtPaths:tmpPaths toPaths:tmpToPaths progress:progress complete:complete];
    });
}

/** 复制单个文件 */
+ (void)copyItemAtPath:(NSString *)path
                toPath:(NSString *)toPath
               success:(void(^)(NSString *destinationPath))success
               failure:(void(^)(NSString *orginalPath, NSString *destinationPath, NSError *error))failure{
    
    [self _copyItemAtPath:path toPath:toPath success:^(NSString *destinationPath) {
        
        dispatch_async(dispatch_get_main_queue(), ^{
            
            !success ? : success(destinationPath);
        });
        
    } failure:^(NSString *orginalPath, NSString *destinationPath, NSError *error) {
        
        dispatch_async(dispatch_get_main_queue(), ^{
            
            !failure ? : failure(orginalPath, destinationPath, error);
        });
    }];
}

/** 批量复制文件 */
+ (void)multiCopyItemAtPaths:(NSArray <NSString *> *)paths
                     toPaths:(NSArray <NSString *> *)toPaths
                    progress:(void(^)(CGFloat progress))progress
                    complete:(void(^)(NSArray <NSString *> *successPaths, NSArray <NSString *> *failurePaths))complete{
    
    if (paths.count != toPaths.count) {
        
        !complete ? : complete(nil, nil);
        
        return;
    }
    
    [self _multiCopyItemAtPaths:paths toPaths:toPaths progress:progress complete:complete];
}

+ (void)_multiCopyItemAtPaths:(NSArray <NSString *> *)paths
                      toPaths:(NSArray <NSString *> *)toPaths
                     progress:(void(^)(CGFloat progress))progress
                     complete:(void(^)(NSArray <NSString *> *successPaths, NSArray <NSString *> *failurePaths))complete{
    
    static NSMutableArray *multiCopySuccessArr = nil;
    
    static NSMutableArray *multiCopyFailureArr = nil;
    
    if (!multiCopySuccessArr) {
        
        multiCopySuccessArr = [NSMutableArray array];
    }
    
    if (!multiCopyFailureArr) {
        
        multiCopyFailureArr = [NSMutableArray array];
    }
    
    if (paths.count <= 0) {
        
        dispatch_async(dispatch_get_main_queue(), ^{
           
            !complete ? : complete(multiCopySuccessArr, multiCopyFailureArr);
            
            multiCopySuccessArr = nil;
            multiCopyFailureArr = nil;
        });
        
        return;
    }
    
    NSMutableArray *tmpPaths = [NSMutableArray arrayWithArray:paths];
    NSMutableArray *tmpToPaths = [NSMutableArray arrayWithArray:toPaths];
    
    [self _copyItemAtPath:tmpPaths.firstObject toPath:tmpToPaths.firstObject success:^(NSString *destinationPath) {
        
        [multiCopySuccessArr addObject:destinationPath];
        
        [tmpPaths removeObjectAtIndex:0];
        [tmpToPaths removeObjectAtIndex:0];
        
        CGFloat finishCount = (multiCopySuccessArr.count + multiCopyFailureArr.count) * 1.0 ;
        
        !progress ? : progress(finishCount / ((finishCount + multiCopyFailureArr.count) * 1.0));
        
        [self _multiCopyItemAtPaths:tmpPaths toPaths:tmpToPaths progress:progress complete:complete];
        
    } failure:^(NSString *orginalPath, NSString *destinationPath, NSError *error) {
        
        [multiCopyFailureArr addObject:destinationPath];
        
        [tmpPaths removeObjectAtIndex:0];
        [tmpToPaths removeObjectAtIndex:0];
        
        CGFloat finishCount = (multiCopySuccessArr.count + multiCopyFailureArr.count) * 1.0 ;
        
        !progress ? : progress(finishCount / ((finishCount + multiCopyFailureArr.count) * 1.0));
        
        [self _multiCopyItemAtPaths:tmpPaths toPaths:tmpToPaths progress:progress complete:complete];
    }];
}

/** 保存文件 */
+ (void)saveData:(NSData *)data
          toPath:(NSString *)toPath
         success:(void(^)(NSString *destinationPath))success
         failure:(void(^)(NSString *destinationPath, NSError *error))failure{
    
    if (!data) {
        
        !failure ? : failure(toPath, [NSError errorWithDomain:NSCocoaErrorDomain code:-1 userInfo:@{NSLocalizedDescriptionKey : @"传入参数为空"}]);
        
        return;
    }
    
    dispatch_async([JKFileExplorerEngine explorerEngineQueue], ^{
        
        // 检查重名 获取合适的目标路径
        NSString *destinationPath = [self checkDuplicationNameWithFilePath:toPath isFolder:NO];
        
        NSError *error = nil;
        
        // 保存文件
        BOOL flag = [data writeToFile:destinationPath atomically:YES];
        
        if (error || !flag) { // 保存失败
            
            dispatch_async(dispatch_get_main_queue(), ^{
                
                !failure ? : failure(destinationPath, error);
            });
            
        } else { // 保存成功
            
            dispatch_async(dispatch_get_main_queue(), ^{
                
                !success ? : success(destinationPath);
            });
        }
    });
}

+ (NSURLSessionDownloadTask *)downLoadFileWithUrl:(NSString *)url
                                        directory:(NSString *)directory
                                         fileName:(NSString *)fileName
                                         progress:(void (^)(NSProgress *downloadProgress))progress
                                completionHandler:(void(^)(NSURLResponse *response, NSURL *filePath, NSError *error))completionHandler{
    
#if __has_include(<AFNetworking/AFNetworking.h>) || __has_include("AFNetworking.h")

    if (!url || !directory || !fileName) {
        
        !completionHandler ? : completionHandler(nil, nil, [NSError errorWithDomain:NSCocoaErrorDomain code:-1 userInfo:@{NSLocalizedDescriptionKey : @"One or more parameter is nil!"}]);
        
        return nil;
    }
    
    BOOL isDirectory = NO;
    
    BOOL flag = [[NSFileManager defaultManager] fileExistsAtPath:directory isDirectory:&isDirectory];
    
    if (!flag || !isDirectory) {
        
        if (![[NSFileManager defaultManager] createDirectoryAtPath:directory withIntermediateDirectories:YES attributes:nil error:nil]) {
            
            NSLog(@"创建文件夹失败!");
            
            !completionHandler ? : completionHandler(nil, nil, [NSError errorWithDomain:NSCocoaErrorDomain code:-1 userInfo:@{NSLocalizedDescriptionKey : @"Create directory failed!"}]);
            
            return nil;
        }
    }
    
    NSString *toPath = [directory stringByAppendingPathComponent:fileName];
    
    NSString *destinationPath = [self checkDuplicationNameWithFilePath:toPath isFolder:NO];
    
    NSURL *fileURL = [NSURL fileURLWithPath:destinationPath];
    
    NSURLSessionDownloadTask *downloadTask = [[AFHTTPSessionManager manager] downloadTaskWithRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:url]] progress:progress destination:^NSURL * _Nonnull(NSURL * _Nonnull targetPath, NSURLResponse * _Nonnull response) {
        
        NSLog(@"%@", targetPath);
        
        return fileURL;
        
    } completionHandler:^(NSURLResponse * _Nonnull response, NSURL * _Nullable filePath, NSError * _Nullable error) {
        
        !completionHandler ? : completionHandler(response, filePath, error);
        
        if (error) {
            
            NSLog(@"下载失败！");
            
            [JKFileManager removeItemAtPath:filePath.path];
            
            return;
        }
        
        NSLog(@"%@", response);
    }];
    
    [downloadTask resume];
    
    return downloadTask;
    
#else
    
    !completionHandler ? : completionHandler(nil, nil, [NSError errorWithDomain:NSCocoaErrorDomain code:-1 userInfo:@{NSLocalizedDescriptionKey : @"AFNetworking is not inluded!"}]);
    
    return nil;
    
#endif
}

#pragma mark
#pragma mark - 获取当前磁盘信息

/// 获取磁盘信息，注意回调是在子线程
+ (void)checkDiskSizeComplete:(void(^)(NSString *totalSize, NSString *usedSize, NSString *freeSize))complete{
    
    dispatch_async([self explorerEngineQueue], ^{
        
        int64_t total = [self getTotalDiskSpace];
        int64_t free = [self getFreeDiskSpace];
        int64_t used = total - free;
        
        NSString *totalSize = [NSByteCountFormatter stringFromByteCount:total countStyle:NSByteCountFormatterCountStyleFile];
        
        NSString *usedSize  = [NSByteCountFormatter stringFromByteCount:used countStyle:NSByteCountFormatterCountStyleFile];
        
        NSString *freeSize  = [NSByteCountFormatter stringFromByteCount:free countStyle:NSByteCountFormatterCountStyleFile];
        
        !complete ? : complete(totalSize, usedSize, freeSize);
    });
}

+ (int64_t)getTotalDiskSpace {
    
    NSError *error = nil;
    
    NSDictionary *attrs = [[NSFileManager defaultManager] attributesOfFileSystemForPath:NSHomeDirectory() error:&error];
    
    if (error) return -1;
    
    int64_t space =  [[attrs objectForKey:NSFileSystemSize] longLongValue];
    
    if (space < 0) space = -1;
    
    return space;
}

+ (int64_t)getFreeDiskSpace {
    
    //    if (@available(iOS 11.0, *)) {
    //        NSError *error = nil;
    //        NSURL *testURL = [NSURL URLWithString:NSHomeDirectory()];
    //
    //        NSDictionary *dict = [testURL resourceValuesForKeys:@[NSURLVolumeAvailableCapacityForImportantUsageKey] error:&error];
    //
    //        return (int64_t)dict[NSURLVolumeAvailableCapacityForImportantUsageKey];
    //
    //
    //    } else {
    
    NSError *error = nil;
    
    NSDictionary *attrs = [[NSFileManager defaultManager] attributesOfFileSystemForPath:NSHomeDirectory() error:&error];
    
    if (error) return -1;
    
    int64_t space =  [[attrs objectForKey:NSFileSystemFreeSize] longLongValue];
    
    if (space < 0) space = -1;
    
    return space;
    //    }
}


#pragma mark
#pragma mark - Private Function

/** 复制文件 */
+ (void)_copyItemAtPath:(NSString *)path
                 toPath:(NSString *)toPath
                success:(void(^)(NSString *destinationPath))success
                failure:(void(^)(NSString *orginalPath, NSString *destinationPath, NSError *error))failure{
    
    dispatch_async([JKFileExplorerEngine explorerEngineQueue], ^{
        
        // 检查重名 获取合适的目标路径
        NSString *destinationPath = [self checkDuplicationNameWithFilePath:toPath sourceFilePath:path];
        
        NSError *error = nil;
        
        // 复制文件
        BOOL flag = [JKFileManager copyItemAtPath:path toPath:destinationPath error:&error];
        
        if (error || !flag) { // 复制失败
            
            !failure ? : failure(path, destinationPath, error);
            
        } else { // 复制成功
            
            !success ? : success(destinationPath);
        }
    });
}
@end
